/**
* Conjunto de funciones para facilitar el uso de CORBA.
*
* @author Carlos Rodriguez Dominguez
* @date 05/11/2008
*/

#ifndef _CORBA_UTIL_H_
#define _CORBA_UTIL_H_

#include "omniORB4/CORBA.h"

namespace auxiliary {

	/**
	* Funcion que permite resolver las referencias iniciales
	* a un servicio de CORBA. Es un template cuyo argumento
	* es el tipo asociado al servicio a resolver.
	*
	* @param orb Orbe de CORBA ya inicializado
	* @param id Nombre del servicio a resolver
	* @return Puntero a un objeto con el tipo asociado al servicio a
	*         resolver
	*/
	template<class T>
	typename T::_ptr_type
	resolve_init(CORBA::ORB_ptr orb, const char* id)
	{
		CORBA::Object_var obj;
	
		try {
			obj = orb->resolve_initial_references(id);
		} 
		catch(const CORBA::ORB::InvalidName& e)
		{
			printf("%s\n", e._name());
			fflush(stdout);
			throw;
		}
		catch(const CORBA::Exception& e)
		{
			printf("%s\n", e._name());
			fflush(stdout);
			throw 0;
		}
		typename T::_var_type ref;
		try {
			ref = T::_narrow(obj);
		}
		catch(const CORBA::Exception& e)
		{
			printf("%s\n", e._name());
			fflush(stdout);
			throw 0;
		}
		if (CORBA::is_nil(ref))
		{
			printf("Ref nil R.I. 1\n");
			fflush(stdout);
			throw 0;
		}
	
		return ref._retn();
	}

	/**
	* Comprueba si un nombre esta registrado en el NameService y en
	* caso afirmativo devuelve un puntero a una instancia del objeto
	* asociado a ese nombre.
	*
	* @param nc Contexto CORBA para el nombre a buscar
	* @param name Nombre del objeto a buscar
	* @return Puntero a la instancia del objeto asociado al nombre
	*/
	template<class T>
	typename T::_ptr_type
	resolve_name(CosNaming::NamingContext_ptr nc, const CosNaming::Name& name)
	{
		CORBA::Object_var obj;
		try{
			obj = nc->resolve(name);
		}
		catch(const CosNaming::NamingContext::NotFound& e)
		{
			printf("%s\n", e._name());
			fflush(stdout);
			throw;
		}
		catch(const CORBA::Exception& e)
		{
			printf("%s\n", e._name());
			fflush(stdout);
			throw 0;
		}
		if (CORBA::is_nil(obj))
		{
			printf("Ref nil R.N. 1\n");
			fflush(stdout);
			throw 0;
		}
		typename T::_var_type ref;
		try{
			ref = T::_narrow(obj);
		}
		catch(const CORBA::Exception& e)
		{
			printf("%s\n", e._name());
			fflush(stdout);
			throw 0;
		}
		if (CORBA::is_nil(ref))
		{
			printf("Ref nil R.N. 2\n");
			fflush(stdout);
			throw 0;
		}
	
		return ref._retn();
	}

	/**
	* Asocia un objeto a un nombre y a un contexto de nombres en el NameService
	*
	* @param orb Orbe de CORBA ya inicializado
	* @param objref Referencia al objeto que se desea registrar en el NameService
	* @param contextName Contexto de nombres del nombre a registrar
	* @param objectName Nombre del objeto a registrar
	* @return True si se registro con exito. False en caso contrario.
	*/
	template <class T>
	CORBA::Boolean bind_object_to_name(CORBA::ORB_ptr orb, typename T::_ptr_type objref, 
										CosNaming::Name contextName, CosNaming::Name objectName)
	{
		CosNaming::NamingContext_var rootContext = resolve_init<CosNaming::NamingContext>(orb, "NameService");

		try {
			CosNaming::NamingContext_var testContext;
			try {
				testContext = rootContext->bind_new_context(contextName);
			}
			catch(CosNaming::NamingContext::AlreadyBound& ex) 
			{
				CORBA::Object_var obj;
				obj = rootContext->resolve(contextName);
				testContext = CosNaming::NamingContext::_narrow(obj);
				if( CORBA::is_nil(testContext) ) 
				{
					printf("Error Context\n");
					return false;
				}
			}

			try {
				testContext->bind(objectName, objref);
			}
			catch(CosNaming::NamingContext::AlreadyBound& ex) 
			{
				testContext->rebind(objectName, objref);
			}
		}
		catch(CORBA::TRANSIENT& ex) 
		{
			printf("%s\n", ex._name());
			return false;
		}
		catch(CORBA::SystemException& ex) 
		{
			printf("%s\n", ex._name());
			return false;
		}
	
		return true;
	}
}

#endif
